/**
 * 
 */
package com.fpt.edu.vn.h2tv.service;

import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.List;

import javax.activity.InvalidActivityException;
import javax.persistence.EntityManager;
import javax.persistence.EntityTransaction;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.fpt.edu.vn.h2tv.common.IOrderStatus;
import com.fpt.edu.vn.h2tv.common.IStatusCode;
import com.fpt.edu.vn.h2tv.dao.EntityManagerHelper;
import com.fpt.edu.vn.h2tv.dao.ITbBookDAO;
import com.fpt.edu.vn.h2tv.dao.TbAccountDAO;
import com.fpt.edu.vn.h2tv.dao.TbBookDAO;
import com.fpt.edu.vn.h2tv.dao.TbOrderDAO;
import com.fpt.edu.vn.h2tv.dao.TbOrderDetailDAO;
import com.fpt.edu.vn.h2tv.dao.TbPaymentMethodDAO;
import com.fpt.edu.vn.h2tv.dao.TbShippingMethodDAO;
import com.fpt.edu.vn.h2tv.dao.entity.TbBook;
import com.fpt.edu.vn.h2tv.dao.entity.TbOrder;
import com.fpt.edu.vn.h2tv.dao.entity.TbOrderDetail;
import com.fpt.edu.vn.h2tv.dao.entity.TbPaymentMethod;
import com.fpt.edu.vn.h2tv.dao.entity.TbShippingMethod;
import com.fpt.edu.vn.h2tv.dto.Book;
import com.fpt.edu.vn.h2tv.dto.Cart;
import com.fpt.edu.vn.h2tv.dto.CartItem;
import com.fpt.edu.vn.h2tv.dto.CartItemStatus;
import com.fpt.edu.vn.h2tv.dto.CartResponse;
import com.fpt.edu.vn.h2tv.dto.Orders;
import com.fpt.edu.vn.h2tv.dto.PaymentMethod;
import com.fpt.edu.vn.h2tv.dto.ShippingMethod;
import com.fpt.edu.vn.h2tv.exception.BookNotFoundException;
import com.fpt.edu.vn.h2tv.exception.MissingParamException;
import com.fpt.edu.vn.h2tv.exception.MissingParameterException;
import com.fpt.edu.vn.h2tv.mapper.BookMapper;
import com.fpt.edu.vn.h2tv.mapper.OrderMapper;
import com.fpt.edu.vn.h2tv.mapper.PaymentMethodMapper;
import com.fpt.edu.vn.h2tv.mapper.ShippingMethodMapper;

/**
 * @author niteha
 * 
 */
public final class CartService {

	private static final Logger LOGGER = LoggerFactory.getLogger(CartService.class);

	private CartService() {
	}

	public static CartResponse add(UserSessionData userSessionData, int bookId) {

		Cart userCart = userSessionData.getCart();
		try {

			if (userSessionData.getCart() == null) {
				List<CartItem> cartItemList = new ArrayList<CartItem>();
				userCart = new Cart();
				userCart.setCartItemList(cartItemList);
				userSessionData.setCart(userCart);
			}

			ITbBookDAO bookDAO = new TbBookDAO();
			TbBook bookPE = bookDAO.findById(bookId);
			Book bookDTO = BookMapper.toDTO(bookPE);
			if (bookPE == null) {
				throw new BookNotFoundException(
						"Cannot find book with book ID: " + bookId);
			} else {
				int index = getCartItemIndexContainBook(userCart.getCartItemList(), bookDTO);
				if (index == -1) {
					CartItem cartItem = new CartItem();
					cartItem.setBook(bookDTO);
					cartItem.setQuanity(1);
					userCart.getCartItemList().add(cartItem);
				} else {
					userCart.getCartItemList().get(index).setQuanity(
							userCart.getCartItemList().get(index).getQuanity() + 1);
				}
			}
		} catch (Exception e) {
			return generateCartResponse(userCart, null, null, null, null, e);
		}

		return generateCartResponse(userCart, null, null, null, null);
	}

	public static CartResponse update(UserSessionData userSessionData,
			Cart updateCart) {
		userSessionData.setCart(updateCart);

		return generateCartResponse(userSessionData.getCart(), null, null, null, null);
	}

	public static CartResponse delete(UserSessionData userSessionData,
			CartItem cartItem) {

		Cart userCart = userSessionData.getCart();
		try {

			if (userCart == null) {
				throw new InvalidActivityException("User does not have cart");
			} else {
				userCart.getCartItemList().remove(cartItem);
			}
		} catch (Exception e) {
			return generateCartResponse(userCart, null, null, null, null, e);
		}

		return generateCartResponse(userCart, null, null, null, null);
	}

	public static CartResponse clear(UserSessionData userSessionData) {

		Cart userCart = userSessionData.getCart();
		if (userCart != null) {
			userCart.getCartItemList().clear();
		}

		return generateCartResponse(userCart, null, null, null, null);
	}

	public static CartResponse get(UserSessionData userSessionData) {

		Cart userCart = userSessionData.getCart();

		return generateCartResponse(userCart, null, null, null, null);
	}

	public static CartResponse checkout(UserSessionData userSessionData,
			Cart cart) {

		try {

			if (userSessionData.getCart().getOrder() == null) {
				throw new MissingParamException("Node <order> is missing.");
			}
			// construct order
			Orders orderDTO = userSessionData.getCart().getOrder();
			TbOrder orderPE = OrderMapper.toPE(orderDTO);
			TbOrderDAO orderDAO = new TbOrderDAO();
			orderDAO.save(orderPE);

			// validate/renew cart item
			TbBookDAO bookDAO = new TbBookDAO();
			TbOrderDetailDAO orderDetailDAO = new TbOrderDetailDAO();
			TbBook bookPE;
			Book bookDTO;
			TbOrderDetail orderDetailPE;
			CartItemStatus status;
			double totalPrice = 0;
			for (CartItem cartItem : cart.getCartItemList()) {
				bookPE = bookDAO.findById(cartItem.getBook().getBookId());
				if (bookPE != null) {
					bookDTO = BookMapper.toDTO(bookPE);
					cartItem.setBook(bookDTO);
	
					status = new CartItemStatus();
					status.setStatus(1);
					cartItem.setStatus(status);
	
					totalPrice += bookDTO.getPrice() * cartItem.getQuanity();

					
				} else {
					status = new CartItemStatus();
					status.setStatus(-1);
					cartItem.setStatus(status);
				}
			}
			cart.setTotalPrice(totalPrice);

			// add cart to session
			userSessionData.setCart(cart);

		} catch (Exception e) {
			// add cart to session
			userSessionData.setCart(cart);
			return generateCartResponse(cart, null, null, null, null, e);
		}

		return generateCartResponse(cart, null, null, null, null);
	}

	public static void main(String[] args) {

		TbOrder orderPE = new TbOrder();
		orderPE.setOrderdate(new Timestamp(System.currentTimeMillis()));
		orderPE.setStatus(IOrderStatus.NOT_PROCESS);
		orderPE.setTbAccount(new TbAccountDAO().findById(1l));
		orderPE.setShippingmethodid(Short.valueOf("1"));
		orderPE.setPaymentmethodid(Short.valueOf("1"));
		orderPE.setTotalprice(100.0);
		orderPE.setStatus(1);

		TbOrderDetail orderDetail = new TbOrderDetail();
		orderDetail.setQuantity(1);
		TbBook book = new TbBook();
		book.setBooktid(1);
		orderDetail.setTbBook(book);
		List<TbOrderDetail> orderDetailList = new ArrayList<TbOrderDetail>(1);
		orderPE.setTbOrderDetails(orderDetailList);

		System.out.println("Before: " + orderPE.getOrderid());
		
		TbOrderDAO orderDAO = new TbOrderDAO();
		EntityManager entityManager = EntityManagerHelper.getEntityManager();
		EntityTransaction transaction = entityManager.getTransaction();
		transaction.begin();
		orderDAO.save(orderPE);
		transaction.commit();

		System.out.println("After: " + orderPE.getOrderid());
	}

	public static CartResponse getOrder(String orderId) {

		try {
			TbOrderDAO orderDAO = new TbOrderDAO();
			TbOrder orderPE = orderDAO.findById(Long.valueOf(orderId));

			Orders orderDTO = OrderMapper.toDTO(orderPE);

			Cart cart = new Cart();
			cart.setOrder(orderDTO);
			return generateCartResponse(cart, null, null, null, null);
		} catch (Exception e) {
			return generateCartResponse(null, null, null, null, null, e);
		}
	}

	public static CartResponse getPaymentMethodList() {

		try {
			TbPaymentMethodDAO dao = new TbPaymentMethodDAO();
			List<TbPaymentMethod> paymentMethodPEList = dao.findAll();
			List<PaymentMethod> paymentMethodDTOList = PaymentMethodMapper.toDTOList(paymentMethodPEList);

			return generateCartResponse(null, null, paymentMethodDTOList, null, null);
		} catch (Exception e) {
			return generateCartResponse(null, null, null, null, null, e);
		}
	}

	public static CartResponse getShippingMethodList() {

		try {
			TbShippingMethodDAO dao = new TbShippingMethodDAO();
			List<TbShippingMethod> shippingMethodPEList = dao.findAll();
			List<ShippingMethod> shippingMethodDTOList = ShippingMethodMapper.toDTOList(shippingMethodPEList);

			return generateCartResponse(null, null, null, null, shippingMethodDTOList);
		} catch (Exception e) {
			return generateCartResponse(null, null, null, null, null, e);
		}
	}

	private static CartResponse generateCartResponse(Cart userCart,
			PaymentMethod paymentMethod,
			List<PaymentMethod> paymentMethodList,
			ShippingMethod shippingMethod,
			List<ShippingMethod> shippingMethodList,
			Exception e) {

		LOGGER.error("Exception: {} - Message: {}", e.getClass().getSimpleName(), e.getMessage());
		CartResponse cartResponse = new CartResponse();
		cartResponse.setCart(userCart);
		cartResponse.setPaymentMethod(paymentMethod);
		cartResponse.setPaymentMethodList(paymentMethodList);
		cartResponse.setErrorMessage(e.getMessage());
		cartResponse.setException(e.getClass().getSimpleName());

		if (e instanceof BookNotFoundException) {
			cartResponse.setStatus(IStatusCode.NOT_FOUND);
		} else if (e instanceof InvalidActivityException) {
			cartResponse.setStatus(IStatusCode.INVALID_ACTIVITY);
		} else if (e instanceof MissingParamException) {
			cartResponse.setStatus(IStatusCode.MISSING_PARAMETER);
		} else {
			cartResponse.setStatus(IStatusCode.PROCESSING_ERROR);
		}

		return cartResponse;
	}

	private static CartResponse generateCartResponse(Cart userCart,
			PaymentMethod paymentMethod,
			List<PaymentMethod> paymentMethodList,
			ShippingMethod shippingMethod,
			List<ShippingMethod> shippingMethodList) {

		CartResponse cartResponse = new CartResponse();
		cartResponse.setCart(userCart);
		cartResponse.setPaymentMethod(paymentMethod);
		cartResponse.setPaymentMethodList(paymentMethodList);
		cartResponse.setShippingMethod(shippingMethod);
		cartResponse.setShippingMethodList(shippingMethodList);
		cartResponse.setStatus(IStatusCode.SUCCESS);

		return cartResponse;
	}

	private static int getCartItemIndexContainBook(List<CartItem> cartItemList, Book book) {
		
		for (int i = 0; i < cartItemList.size(); ++i) {
			if (cartItemList.get(i).getBook().equals(book)) {
				return i;
			}
		}

		return -1;
	}
}
